﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
using MapLibrary.Utility;

namespace GUILibrary
{
    /// <summary>
    /// This represents an general bar that gets "filled" with respect to a reference
    /// to some value.
    /// </summary>
    public class HorizontalFillBar : Component, ActionListener
    {
        /// <summary>
        /// Unique identifier for each bar.  Used for nameing actions.
        /// </summary>
        public static int barId = 0;

        public delegate void BarFilledDelegate(HorizontalFillBar fillBar);

        /// <summary>
        /// This event gets triggered whenever the bar is full.  It is the
        /// responsibility of the listener to then act, possibly emptying the
        /// bar, etc.
        /// </summary>
        public event BarFilledDelegate OnBarFull;

        /// <summary>
        /// The underlying image of the bar.  This gets displayed under the
        /// fillImage.
        /// </summary>
        public string BaseImageName
        {
            get;
            set;
        }

        /// <summary>
        /// The image that will be repeated horizontally to represent "filling"
        /// the bar.
        /// </summary>
        public string FillImageName
        {
            get;
            set;
        }

        /// <summary>
        /// The offset in the base image where we will start drawing the horizontal
        /// bar.
        /// </summary>
        public Vector2 ProgressOffset
        {
            get;
            set;
        }

        /// <summary>
        /// How wide the "progress" area is.
        /// </summary>
        public int EffectiveWidth
        {
            get;
            set;
        }

        /// <summary>
        /// The value to track.  This value determines how full the bar is.
        /// </summary>
        [ContentSerializerIgnore]
        public IntWrapper ValueToTrack
        {
            get { return valueToTrack; }
            set
            {
                valueToTrack = value;
                CheckAndTriggerInitialize();
            }
        }

        /// <summary>
        /// The maximum value for the tracked value.  This determines what percent full
        /// the bar is.
        /// </summary>
        [ContentSerializerIgnore]
        public IntWrapper MaximumValue
        {
            get { return maximumValue; }
            set
            {
                maximumValue = value;
                CheckAndTriggerInitialize();
            }
        }

        /// <summary>
        /// This is the place to pull values from.
        /// </summary>
        [ContentSerializerIgnore]
        public IntWrapper Sink
        {
            get { return sink; }
            set
            {
                sink = value;
                CheckAndTriggerInitialize();
            }
        }

        private Texture2D baseImage;
        private Texture2D fillImage;
        private IntWrapper valueToTrack;
        private IntWrapper maximumValue;
        private IntWrapper sink;

        private int fillImageWidth;
        private TimerUtility fillTimer;

        public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch batch)
        {
            //draw the underlying bar at my position.
            batch.Draw(baseImage, ScreenPosition, Color.White);

            //now draw the fill amount
            float percent = CalculatePercent();
            int numBars = (int)((EffectiveWidth * percent) / fillImageWidth);
            Vector2 startPos = ScreenPosition + ProgressOffset;
            for (int i = 0; i < numBars; i++)
            {
                batch.Draw(fillImage, startPos + (i * new Vector2(fillImageWidth, 0)), Color.White);
            }
        }

        public override void Load(ContentManager cm)
        {
            //initialize some values
            maximumValue = null;
            valueToTrack = null;
            Action = "HorizontalFillBar" + barId++;

            baseImage = cm.Load<Texture2D>(BaseImageName);
            fillImage = cm.Load<Texture2D>(FillImageName);
            fillImageWidth = fillImage.Bounds.Width;
        }

        private float CalculatePercent()
        {
            if (!Initialized)
                return 0.0f;
            else
            {
                return (float)valueToTrack.Value / maximumValue.Value;
            }
        }

        private void CheckAndTriggerInitialize()
        {
            bool initPrev = Initialized;
            Initialized = (maximumValue != null) && (valueToTrack != null) && (sink != null);

            if (Initialized && !initPrev)
            {
                fillTimer = new TimerUtility(UpdateAmounts, (5 * 60) / maximumValue.Value);
            }
        }

        public void UpdateAction(string currentAction)
        {
            //note I only want to execute if I'm initialized.
            if (!Initialized)
                return;

            if (currentAction.Equals(Action))
            {
                //fill bar stuff
                fillTimer.Update();
            }
        }

        public override void UpdateMouseClick(Input.GameInput input)
        {
            Triggered = input.IsLeftMouseButtonDown() && Hovered;
        }

        private void UpdateAmounts()
        {
            if (valueToTrack.Value >= maximumValue.Value)
            {
                if (OnBarFull != null)
                    OnBarFull(this);
            }
            else
            {
                if (sink.Value > 0)
                {
                    valueToTrack.Value += 1;
                    sink.Value -= 1;
                }
            }
        }
    }
}
